package jhavelogger.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Collection;
import java.util.concurrent.BlockingQueue;

import jhavelogger.models.JHaveLog;
import jhavelogger.models.UnparsedLog;
import jhavelogger.parser.LogFactory;

/**
 * A separate thread to handle parsing log files.
 * @author Jared Schlicht
 */
public class LogParsingThread extends Thread {
    private Collection<LogFactory> logFactories;
    private Socket socket;
    private BlockingQueue<JHaveLog> logQueue;
    private BufferedReader reader;
    
    /**
     * Constructs a new LogParsingThread
     * @param logFactories a set of log factories to use to parse log files
     * @param socket the socket to read logs from
     * @param logQueue a threadsafe queue that parsed logs should be sent to
     * @throws IOException if a network error occurred while parsing logs
     */
    public LogParsingThread(Collection<LogFactory> logFactories, Socket socket, BlockingQueue<JHaveLog> logQueue) throws IOException {
	this.logFactories = logFactories;
	this.socket = socket;
	this.logQueue = logQueue;
	this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }

    @Override
    public void run() {
	try {
	    String logLine;
	    while ((logLine = this.reader.readLine()) != null) {
		JHaveLog log = this.parseLog(logLine);
		if (log != null) {
		    this.logQueue.add(log);
		} else {
		}
	    }
	} catch (IOException e) {
	    e.printStackTrace();
	} finally {
	    if (this.socket != null) {
		try {
		    this.socket.close();
		} catch (IOException e) {
		    e.printStackTrace();
		}
	    }
	}
    }
    
    /**
     * Attempts to parse the specified log
     * @param logLine the log to parse
     * @return JHaveLog object or null if this log line could not be parsed
     */
    private JHaveLog parseLog(String logLine) {
	for (LogFactory factory : this.logFactories) {
	    JHaveLog log = factory.create(new UnparsedLog(this.socket.getInetAddress().toString(), logLine));
	    if (log != null) {
		return log;
	    }
	}
	
	return null;
    }
}
